/**
 * JavaScript interface to implement Observer Pattern
 */
function iSubject(__constructor, proto) {
    this.constructor = __constructor;
    if (proto instanceof Object) {
        for (var p in proto) {
            if (proto.hasOwnProperty(p)) {
                this[p] = proto[p];
            }
        }
    }
}
iSubject.prototype = {
    addObserver: function(observer) {
        if (!(observer instanceof iObserver)) {
            throw 'Invalid data type: "iObserver" type needed!';
        }
        if (!(this.observers instanceof Array)) {
            this.observers = [];
        }
        if (typeof this.observers.indexOf == 'function') {
            if (this.observers.indexOf(observer) != -1) {
                return;
            }
        } else {
            var i = this.observers.length;
            while (i--) {
                if (this.observers[i] === observer) {
                    return;
                }
            }
        }
        this.observers.push(observer);
    },

    removeObserver: function(observer) {
        var index;
        if (!(this.observers instanceof Array)) {
            return;
        }
        if (typeof this.observers.indexOf == 'function') {
            index = this.observers.indexOf(observer);
        } else {
            var i = this.observers.length;
            while (i--) {
                if (this.observers[i] === observer) {
                    index = i;
                }
            }
        }
        if (typeof index != 'undefined' && index != -1) {
            return this.observers.splice(index, 1)[0];
        }
    },

    notify: function(event) {
        if (!(this.observers instanceof Array)) {
            return;
        }
        var i  = 0,
            len = this.observers.length;
        for (; i < len; i++) {
            this.observers[i].handle(this, event);
        }
    }
};
function iObserver(__constructor, proto) {
    iSubject.call(this, __constructor, proto);
}
iObserver.prototype.handle = function(subject, event) {};


/**
 * HOW TO USE:
 *
 * // Model
 * function MyModel() {}
 * MyModel.prototype = new iSubject(MyModel, {
 *    start: function() {
 *        this.notify('begin');
 *    },
 *
 *    end: function() {
 *        this.notify('end');
 *    }
 * });
 *
 * // View
 * function MyView() {}
 * MyView.prototype = new iObserver(MyView, {
 *     handle: function(model, event) {
 *         alert('receive event: "' + event + '" @' + (+new Date));
 *     }
 * });
 *
 *
 * // execute
 * var m = new MyModel(),
 *     v = new MyView();
 * 
 * m.addObserver(v);
 * m.start();
 *
 */
